<template>
  <teleport to="#fx-back-top">
    <transition name="back-top">
      <div class="fx-back-top" v-if="currentScrollTop>visibilityHeight"
           :style="backTopStyle"
           @click="backTopClick">
        <slot>
          <div class="fx-back-top-icon">
            <i class="iconfont icon-backtop"/>
          </div>
        </slot>
      </div>
    </transition>
  </teleport>
</template>

<script lang="ts">
import { computed, defineComponent, onBeforeUnmount, onMounted, PropType, ref } from 'vue'
import { useCreateTeleport } from '@/base/hooks'
import { codeRule } from '@/base/types'

interface BackTopProps {
  target: string;
  visibilityHeight: string | number;
  right: string | number;
  bottom: string | number;
}

export default defineComponent({
  name: 'FBackTop',
  props: {
    target: {
      type: String as PropType<string>,
      default: 'body'
    },
    visibilityHeight: {
      type: [String, Number] as PropType<string | number>,
      default: 200
    },
    right: {
      type: [String, Number] as PropType<string | number>,
      default: 20
    },
    bottom: {
      type: [String, Number] as PropType<string | number>,
      default: 20
    }
  },
  setup (props: BackTopProps) {
    // eslint-disable-next-line no-undef
    let backTopTimer: ReturnType<typeof setTimeout>
    useCreateTeleport('fx-back-top', 'id')
    const currentScrollTop = ref<number>(0)

    const handleBackTopScroll = (): void => {
      const targetDom = document.querySelector(props.target) as HTMLElement
      if (!targetDom) return
      currentScrollTop.value = targetDom.scrollTop
    }

    const goToTop = (dom: Element): void => {
      clearInterval(backTopTimer)
      let scrollTop = dom.scrollTop > 200 ? 200 : dom.scrollTop
      backTopTimer = setInterval(() => {
        scrollTop -= 2
        dom.scrollTo(0, scrollTop)
        if (scrollTop <= 0) {
          clearInterval(backTopTimer)
          dom.scrollTo(0, 0)
        }
      })
    }

    const backTopClick = (): void => {
      const targetDom = document.querySelector(props.target)
      if (!targetDom) return
      goToTop(targetDom)
    }

    const backTopStyle = computed(() => {
      const isStringRight = typeof props.right === 'string' && codeRule.test(props.right)
      const isStringBottom = typeof props.bottom === 'string' && codeRule.test(props.bottom)
      return {
        right: isStringRight ? props.right : `${props.right}px`,
        bottom: isStringBottom ? props.bottom : `${props.bottom}px`
      }
    })

    onMounted(() => {
      const targetDom = document.querySelector(props.target) as HTMLElement
      if (!targetDom) return
      targetDom.addEventListener('scroll', handleBackTopScroll)
    })

    onBeforeUnmount(() => {
      const targetDom = document.querySelector(props.target) as HTMLElement
      if (!targetDom) return
      targetDom.removeEventListener('scroll', handleBackTopScroll)
    })

    return {
      backTopStyle,
      currentScrollTop,
      backTopClick
    }
  }
})
</script>
